home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 3 / CD ACTUAL 3.iso / linux / incoming / libgr-2.000 / libgr-2 / libgr-2.0.3 / rle / scanargs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-14  |  22.3 KB  |  945 lines

  1. /* 
  2.  * scanargs.c,v 1.1.1.1 1995/08/15 02:46:23 neal Exp
  3.  *         Version 7 compatible
  4.  *     Argument scanner, scans argv style argument list.
  5.  * 
  6.  *     Some stuff is a kludge because sscanf screws up
  7.  * 
  8.  *     Gary Newman - 10/4/1979 - Ampex Corp. 
  9.  * 
  10.  *     Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
  11.  *     add args introduced by     a flag, add qscanargs call,
  12.  *     allow empty flags.
  13.  * 
  14.  *     If you make improvements we'd like to get them too.
  15.  *     Jay Lepreau    lepreau@utah-20, decvax!harpo!utah-cs!lepreau
  16.  *     Spencer Thomas    thomas@utah-20, decvax!harpo!utah-cs!thomas 
  17.  * 
  18.  *    (I know the code is ugly, but it just grew, you see ...)
  19.  * 
  20.  * Modified by:    Spencer W. Thomas
  21.  *     Date:    Feb 25 1983
  22.  * 1. Fixed scanning of optional args.  Now args introduced by a flag
  23.  *    must follow the flag which introduces them and precede any other
  24.  *    flag argument.  It is still possible for a flag introduced
  25.  *    argument to be mistaken for a "bare" argument which occurs
  26.  *    earlier in the format string.  This implies that flags may not
  27.  *    be conditional upon other flags, and a message will be generated
  28.  *    if this is attempted.
  29.  * 
  30.  * 2. Usage message can be formatted by inserting newlines, tabs and
  31.  *    spaces into the format string.  This is especially useful for
  32.  *    long argument lists.
  33.  * 
  34.  * 3. Added n/N types for "numeric" args.  These args are scanned
  35.  *    using the C language conventions - a number starting 0x is
  36.  *    hexadecimal, a number starting with 0 is octal, otherwise it is
  37.  *    decimal.
  38.  *
  39.  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  40.  *  to have all "void" functions so declared.
  41.  */
  42.  
  43. #include "rle_config.h"
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #ifndef USE_STDARG
  47. #include <varargs.h>
  48. #else
  49. #include <stdarg.h>
  50. #endif
  51.  
  52. typedef char bool;
  53. /* 
  54.  * An explicit assumption is made in this code that all pointers look
  55.  * alike, except possible char * pointers.
  56.  */
  57. typedef int *ptr;
  58.  
  59. #define YES 1
  60. #define NO 0
  61. #define ERROR(msg)  {fprintf(stderr, "%s\n", msg); goto error; }
  62.  
  63. /* 
  64.  * Storage allocation macros
  65.  */
  66. #define NEW( type, cnt )    (type *) malloc( (cnt) * sizeof( type ) )
  67. #define RENEW( type, ptr, cnt )    (type *) realloc( ptr, (cnt) * sizeof( type ) )
  68.  
  69. #if defined(c_plusplus) && !defined(USE_PROTOTYPES)
  70. #define USE_PROTOTYPES
  71. #endif
  72.  
  73. #ifndef USE_PROTOTYPES
  74. static char * prformat();
  75. static int isnum();
  76. static int    _do_scanargs();
  77. void        scan_usage();
  78. #else
  79. static CONST_DECL char * prformat( CONST_DECL char *, int );
  80. static int isnum( CONST_DECL char *, int, int );
  81. static int    _do_scanargs( int argc, char **argv, CONST_DECL char *format,
  82.                   va_list argl );
  83. void        scan_usage( char **, CONST_DECL char * );
  84. #endif
  85.  
  86. /* 
  87.  * Argument list is (argc, argv, format, ... )
  88.  */
  89. int
  90. #ifndef USE_STDARG
  91. scanargs ( va_alist )
  92. va_dcl
  93. #else
  94. scanargs ( int argc, char **argv, CONST_DECL char *format, ... )
  95. #endif /* !USE_STDARG */
  96. {
  97.     va_list argl;
  98.     int retval;
  99. #ifndef USE_STDARG
  100.     int argc;
  101.     char ** argv;
  102.     CONST_DECL char *format;
  103.  
  104.     va_start( argl );
  105.     argc = va_arg( argl, int );
  106.     argv = va_arg( argl, char ** );
  107.     format = va_arg( argl, CONST_DECL char * );
  108. #else
  109.     va_start( argl, format );
  110. #endif
  111.     retval = _do_scanargs( argc, argv, format, argl );
  112.     va_end( argl );
  113.     return retval;
  114. }
  115.     
  116. /* 
  117.  * This routine is necessary because of a pyramid compiler botch that
  118.  * uses parameter registers in a varargs routine.  The extra
  119.  * subroutine call isolates the args on the register stack so they
  120.  * don't get trashed.
  121.  */
  122.  
  123. static int
  124. _do_scanargs( argc, argv, format, argl )
  125. int     argc;            /* Actual arguments */
  126. char  **argv;
  127. CONST_DECL char   *format;
  128. va_list argl;
  129. {
  130.  
  131.     register    check;            /* check counter to be sure all argvs
  132.                        are processed */
  133.     register CONST_DECL char  *cp;
  134.     register    cnt;
  135.     int        optarg = 0;            /* where optional args start */
  136.     int        nopt = 0;
  137.     char    tmpflg,            /* temp flag */
  138.         typchr;            /* type char from format string */
  139.     char    c;
  140.     bool  * arg_used;            /* array of flags */
  141.     ptr        aptr = 0;            /* pointer to return loc */
  142.  
  143.     bool    required;
  144.     int        excnt;            /* which flag is set */
  145.     bool    exflag;            /* when set, one of a set of exclusive
  146.                        flags is set */
  147.  
  148.     bool    list_of;            /* set if parsing off a list of args */
  149.     bool    comma_list;            /* set if AT&T style multiple args */
  150.     bool    no_usage;            /* If set, don't print usage msg. */
  151.     bool    help = NO;            /* If set, always print usage. */
  152.     int      * cnt_arg = 0;        /* where to stuff list count */
  153.     int        list_cnt;            /* how many in list */
  154.     /* These are used to build return lists */
  155.     char ** strlist = 0;
  156.     int   * intlist = 0;
  157.     long  * longlist = 0;
  158.     float * fltlist = 0;
  159.     double *dbllist = 0;
  160.     char  * argp;            /* Pointer to argument. */
  161.  
  162.     CONST_DECL char   *ncp;        /* remember cp during flag scanning */
  163.     static char   cntrl[7] = "%  %1s";    /* control string for scanf's */
  164.     char    junk[2];            /* junk buffer for scanf's */
  165.  
  166.     /* Set up for argument counting. */
  167.     arg_used = NEW( bool, argc );
  168.     if (arg_used == NULL)
  169.     {
  170.     fprintf(stderr, "malloc failed in scanargs, exiting\n");
  171.     exit(-1);
  172.     }
  173.     else
  174.     {
  175.     for (cnt=0; cnt<argc; cnt++)
  176.         arg_used[cnt] = NO;
  177.     }
  178.     check = 0;
  179.  
  180.     /* Scan for -help in arg list. */
  181.     for ( cnt=1; cnt<argc; cnt++ )
  182.     if ( strcmp( argv[cnt], "-help" ) == 0 )
  183.     {
  184.         check += cnt;
  185.         arg_used[cnt] = YES;
  186.         if ( argc == 2 )
  187.         {
  188.         scan_usage( argv, format );
  189.         return 0;
  190.         }
  191.         else
  192.         help = YES;
  193.     }
  194.  
  195.     /* If format string ends in @, don't print a usage message. */
  196.     no_usage = *(format + strlen( format ) - 1) == '&';
  197.  
  198.     cp = format;
  199.     /* 
  200.      * Skip program name
  201.      */
  202.     while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
  203.     cp++;
  204.  
  205.     while (*cp)
  206.     {
  207.     required = NO;            /* reset per-arg flags */
  208.     list_of = NO;
  209.     comma_list = NO;
  210.     list_cnt = 0;
  211.     switch (*(cp++))
  212.     {
  213.         default:             /* all other chars */
  214.         break;
  215.         case ' ':            /* separators */
  216.         case '\t':
  217.         case '\n':
  218.         optarg = 0;        /* end of optional arg string */
  219.         break;
  220.  
  221.         case '(':            /* Surrounds a comment. */
  222.         {
  223.         int depth = 1;        /* Count parenthesis depth. */
  224.         while ( *cp && depth > 0 )
  225.             switch ( *(cp++) )
  226.             {
  227.             case '(':    depth++;        break;
  228.             case ')':    depth--;        break;
  229.             }
  230.         break;
  231.         }
  232.  
  233.         case '!':             /* required argument */
  234.         required = YES;
  235.         case '%':             /* not required argument */
  236. reswitch:                /* after finding '*' or ',' */
  237.         switch (typchr = *(cp++))
  238.         {
  239.             case ',':        /* argument is AT&T list of things */
  240.             comma_list = YES;
  241.             case '*':        /* argument is list of things */
  242.             list_of = YES;
  243.             list_cnt = 0;    /* none yet */
  244.             cnt_arg = va_arg( argl, int *);    /* item count * here */
  245.             goto reswitch;    /* try again */
  246.  
  247.             case '$':        /* "rest" of argument list */
  248.             while ( argc > 1 && !arg_used[argc-1] )
  249.                 argc--;    /* find last used argument */
  250.             *va_arg( argl, int * ) = argc;
  251.             break;
  252.  
  253.             case '&':        /* Return unused args. */
  254.             /* Count how many.  Always include argv[0]. */
  255.             for ( nopt = cnt = 1; cnt < argc; cnt++ )
  256.                 if ( !arg_used[cnt] )
  257.                 nopt++;
  258.             if ( nopt == 1 )
  259.                 nopt = 0;    /* Special case for no args. */
  260.             if ( nopt > 0 )
  261.             {
  262.                 strlist = NEW( char *, nopt + 1 );
  263.                 /* Copy program name, for sure. */
  264.                 strlist[0] = argv[0];
  265.                 for ( nopt = cnt = 1; cnt < argc; cnt++ )
  266.                 if ( !arg_used[cnt] )
  267.                 {
  268.                     strlist[nopt++] = argv[cnt];
  269.                     check += cnt;
  270.                     arg_used[cnt] = 1;
  271.                 }
  272.                 strlist[nopt] = NULL;
  273.             }
  274.             else
  275.                 strlist = NULL;    /* No args, return empty. */
  276.  
  277.             /* Return count and arg list. */
  278.             *va_arg( argl, int * ) = nopt;
  279.             *va_arg( argl, char *** ) = strlist;
  280.             break;
  281.  
  282.             case '-':         /* argument is flag */
  283.             if (optarg > 0)
  284.                 ERROR("Format error: flag conditional on flag not allowed");
  285.  
  286.             /* go back to label */
  287.             ncp = cp-1;    /* remember */
  288.             cp -= 3;
  289.             for (excnt = exflag = 0
  290.                 ; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
  291.                 (--cp, excnt++))
  292.             {
  293.                 for (cnt = optarg+1; cnt < argc; cnt++)
  294.                 {
  295.                 /* flags all start with - */
  296.                 if (*argv[cnt] == '-' && !arg_used[cnt] &&
  297.                     !isdigit(argv[cnt][1]))
  298.                     if (*(argv[cnt] + 1) == *cp)
  299.                     {
  300.                     if (*(argv[cnt] + 2) != 0)
  301.                         ERROR ("extra flags ignored");
  302.                     if (exflag)
  303.                         ERROR ("more than one exclusive flag chosen");
  304.                     exflag++;
  305.                     required = NO;
  306.                     check += cnt;
  307.                     arg_used[cnt] = 1;
  308.                     nopt = cnt;
  309.                     *va_arg( argl, int *) |= (1 << excnt);
  310.                     break;
  311.                     }
  312.                 }
  313.             }
  314.             if (required)
  315.                 ERROR ("flag argument missing");
  316.             cp = ncp;
  317.             /* 
  318.              * If none of these flags were found, skip any
  319.              * optional arguments (in the varargs list, too).
  320.              */
  321.             if (!exflag)
  322.             {
  323.                 (void)va_arg( argl, int * );/* skip the arg, too */
  324.                 while (*++cp && ! isspace(*cp))
  325.                 if (*cp == '!' || *cp == '%')
  326.                 {
  327.                     if ( *++cp == '*' || *cp == ',' )
  328.                     {
  329.                     cp++;
  330.                     (void)va_arg( argl, int * );
  331.                     }
  332.                     /* 
  333.                      * Assume that char * might be a
  334.                      * different size, but that all
  335.                      * other pointers are same size.
  336.                      */
  337.                     if ( *cp == 's' )
  338.                     (void)va_arg( argl, char * );
  339.                     else
  340.                     (void)va_arg( argl, ptr );
  341.                 }
  342.             }
  343.             else
  344.             {
  345.                 optarg = nopt;
  346.                 cp++;    /* skip over - */
  347.             }
  348.  
  349.             break;
  350.  
  351.             case 's':         /* char string */
  352.             case 'd':         /* decimal # */
  353.             case 'o':         /* octal # */
  354.             case 'x':         /* hexadecimal # */
  355.             case 'n':        /* "number" in C syntax */
  356.             case 'f':         /* floating # */
  357.             case 'D':         /* long decimal # */
  358.             case 'O':         /* long octal # */
  359.             case 'X':         /* long hexadecimal # */
  360.             case 'N':        /* long number in C syntax */
  361.             case 'F':         /* double precision floating # */
  362. #if defined(sgi) && !defined(mips)
  363.             /* Fix for broken SGI IRIS 2400/3000 floats */
  364.             if ( typchr == 'F' ) typchr = 'f';
  365. #endif /* sgi */
  366.             for (cnt = optarg+1; cnt < argc; cnt++)
  367.             {
  368.                 argp = argv[cnt];
  369.  
  370.                 if ( isnum( argp, typchr, comma_list ) )
  371.                 {
  372.                 ;    /* it's ok, then */
  373.                 }
  374.                 else if ( *argp == '-' && argp[1] != '\0' )
  375.                 if ( optarg > 0 ) /* end optional args? */
  376.                 {
  377.                     /* Eat the arg, too, if necessary */
  378.                     if ( list_cnt == 0 )
  379.                     if ( typchr == 's' )
  380.                         (void)va_arg( argl, char * );
  381.                     else
  382.                         (void)va_arg( argl, ptr );
  383.                     break;
  384.                 }
  385.                 else
  386.                     continue;
  387.                 else if ( typchr != 's' )
  388.                 continue;    /* not number, keep looking */
  389.                 
  390.                 /* 
  391.                  * Otherwise usable argument may already
  392.                  * be used.  (Must check this after
  393.                  * checking for flag, though.)
  394.                  */
  395.                 if (arg_used[cnt]) continue;
  396.  
  397.                 /* 
  398.                  * If it's a comma-and-or-space-separated
  399.                  * list then count how many, and separate
  400.                  * the list into an array of strings.
  401.                  */
  402.                 if ( comma_list )
  403.                 {
  404.                 register char * s;
  405.                 int pass;
  406.  
  407.                 /*
  408.                  * Copy the string so we remain nondestructive
  409.                  */
  410.                 s = NEW( char, strlen(argp)+1 );
  411.                 strcpy( s, argp );
  412.                 argp = s;
  413.  
  414.                 /* 
  415.                  * On pass 0, just count them.  On
  416.                  * pass 1, null terminate each string 
  417.                  */
  418.                 for ( pass = 0; pass <= 1; pass++ )
  419.                 {
  420.                     for ( s = argp; *s != '\0'; )
  421.                     {
  422.                     if ( pass )
  423.                         strlist[list_cnt] = s;
  424.                     while ( (c = *s) != '\0' && c != ' ' &&
  425.                         c != '\t' && c != ',' )
  426.                         s++;
  427.                     if ( pass )
  428.                         *s = '\0';
  429.  
  430.                     list_cnt++;    /* count separators */
  431.                     /* 
  432.                      * Two commas in a row give a null
  433.                      * string, but two spaces
  434.                      * don't.  Also skip spaces
  435.                      * after a comma.
  436.                      */
  437.                     if ( c != '\0' )
  438.                         while ( *++s == ' ' || *s == '\t' )
  439.                         ;
  440.                     }
  441.                     if ( pass == 0 )
  442.                     {
  443.                     strlist = NEW( char *, list_cnt );
  444.                     list_cnt = 0;
  445.                     }
  446.                 }
  447.                 }
  448.                 else if ( list_of )
  449.                 list_cnt++;   /* getting them one at a time */
  450.                 /* 
  451.                  * If it's either type of list, then alloc
  452.                  * storage space for the returned values
  453.                  * (except that comma-separated string
  454.                  * lists already are done).
  455.                  */
  456.                 if ( list_of )
  457.                 {
  458.                 if ( list_cnt == 1 || comma_list )
  459.                     switch( typchr )
  460.                     {
  461.                     case 's':
  462.                         if ( !comma_list )
  463.                         strlist = NEW( char *, 1 );
  464.                         aptr = (ptr) &strlist[0];
  465.                         break;
  466.                     case 'n':
  467.                     case 'd':
  468.                     case 'o':
  469.                     case 'x':
  470.                         intlist = NEW( int, list_cnt );
  471.                         aptr = (ptr) &intlist[0];
  472.                         break;
  473.                     case 'N':
  474.                     case 'D':
  475.                     case 'O':
  476.                     case 'X':
  477.                         longlist = NEW( long, list_cnt );
  478.                         aptr = (ptr) &longlist[0];
  479.                         break;
  480.                     case 'f':
  481.                         fltlist = NEW( float, list_cnt );
  482.                         aptr = (ptr) &fltlist[0];
  483.                         break;
  484.                     case 'F':
  485.                         dbllist = NEW( double, list_cnt );
  486.                         aptr = (ptr) &dbllist[0];
  487.                         break;
  488.                     }
  489.                 else
  490.                     switch( typchr )
  491.                     {
  492.                     case 's':
  493.                         strlist = RENEW( char *, strlist,
  494.                                  list_cnt );
  495.                         aptr = (ptr) &strlist[list_cnt-1];
  496.                         break;
  497.                     case 'n':
  498.                     case 'd':
  499.                     case 'o':
  500.                     case 'x':
  501.                         intlist = RENEW( int, intlist,
  502.                                  list_cnt );
  503.                         aptr = (ptr) &intlist[list_cnt-1];
  504.                         break;
  505.                     case 'N':
  506.                     case 'D':
  507.                     case 'O':
  508.                     case 'X':
  509.                         longlist = RENEW( long, longlist,
  510.                                   list_cnt );
  511.                         aptr = (ptr) &longlist[list_cnt-1];
  512.                         break;
  513.                     case 'f':
  514.                         fltlist = RENEW( float, fltlist,
  515.                                  list_cnt );
  516.                         aptr = (ptr) &fltlist[list_cnt-1];
  517.                         break;
  518.                     case 'F':
  519.                         dbllist = RENEW( double, dbllist,
  520.                                  list_cnt );
  521.                         aptr = (ptr) &dbllist[list_cnt-1];
  522.                         break;
  523.                     }
  524.                 }
  525.                 else
  526.                 aptr = va_arg( argl, ptr );
  527.  
  528.                 if ( typchr == 's' )
  529.                 {
  530.                 if ( ! comma_list )
  531.                     *(char **)aptr = argp;
  532.                 }
  533.                 else
  534.                 {
  535.                 nopt = 0;
  536.                 do {
  537.                     /* 
  538.                      * Need to update aptr if parsing
  539.                      * a comma list
  540.                      */
  541.                     if ( comma_list && nopt > 0 )
  542.                     {
  543.                     argp = strlist[nopt];
  544.                     switch( typchr )
  545.                     {
  546.                         case 'n':
  547.                         case 'd':
  548.                         case 'o':
  549.                         case 'x':
  550.                         aptr = (ptr) &intlist[nopt];
  551.                         break;
  552.                         case 'N':
  553.                         case 'D':
  554.                         case 'O':
  555.                         case 'X':
  556.                         aptr = (ptr) &longlist[nopt];
  557.                         break;
  558.                         case 'f':
  559.                         aptr = (ptr) &fltlist[nopt];
  560.                         break;
  561.                         case 'F':
  562.                         aptr = (ptr) &dbllist[nopt];
  563.                         break;
  564.                     }
  565.                     }
  566.                     /* 
  567.                      * Do conversion for n and N types
  568.                      */
  569.                     tmpflg = typchr;
  570.                     if (typchr == 'n' || typchr == 'N' )
  571.                     if (*argp != '0')
  572.                         tmpflg = 'd';
  573.                     else if (*(argp+1) == 'x' ||
  574.                          *(argp+1) == 'X')
  575.                     {
  576.                         tmpflg = 'x';
  577.                         argp += 2;
  578.                     }
  579.                     else
  580.                         tmpflg = 'o';
  581.                     if (typchr == 'N')
  582.                     tmpflg = toupper( tmpflg );
  583.  
  584.  
  585.                     /* put in conversion */
  586.                     if ( isupper( tmpflg ) )
  587.                     {
  588.                     cntrl[1] = 'l';
  589.                     cntrl[2] = tolower( tmpflg );
  590.                     }
  591.                     else
  592.                     {
  593.                     cntrl[1] = tmpflg;
  594.                     cntrl[2] = ' ';
  595.                     }
  596.                     if (sscanf (argp, cntrl, aptr, junk) != 1)
  597.                     ERROR ("Bad numeric argument");
  598.                 } while ( comma_list && ++nopt < list_cnt );
  599.                 }
  600.                 check += cnt;
  601.                 arg_used[cnt] = 1;
  602.                 required = NO;
  603.                 /*
  604.                  * If not looking for multiple args,
  605.                  * then done, otherwise, keep looking.
  606.                  */
  607.                 if ( !( list_of && !comma_list ) )
  608.                 break;
  609.                 else
  610.                 continue;
  611.             }
  612.             if (required)
  613.                 switch (typchr)
  614.                 {
  615.                 case 'x': 
  616.                 case 'X': 
  617.                     ERROR ("missing hexadecimal argument");
  618.                 case 's': 
  619.                     ERROR ("missing string argument");
  620.                 case 'o': 
  621.                 case 'O': 
  622.                     ERROR ("missing octal argument");
  623.                 case 'd': 
  624.                 case 'D': 
  625.                     ERROR ("missing decimal argument");
  626.                 case 'f': 
  627.                 case 'F': 
  628.                     ERROR ("missing floating argument");
  629.                 case 'n':
  630.                 case 'N':
  631.                     ERROR ("missing numeric argument");
  632.                 }
  633.             if ( list_cnt > 0 )
  634.             {
  635.                 *cnt_arg = list_cnt;
  636.                 switch ( typchr )
  637.                 {
  638.                 case 's':
  639.                     *va_arg( argl, char *** ) = strlist;
  640.                     break;
  641.                 case 'n':
  642.                 case 'd':
  643.                 case 'o':
  644.                 case 'x':
  645.                     *va_arg( argl, int ** ) = intlist;
  646.                     break;
  647.                 case 'N':
  648.                 case 'D':
  649.                 case 'O':
  650.                 case 'X':
  651.                     *va_arg( argl, long ** ) = longlist;
  652.                     break;
  653.                 case 'f':
  654.                     *va_arg( argl, float ** ) = fltlist;
  655.                     break;
  656.                 case 'F':
  657.                     *va_arg( argl, double **) = dbllist;
  658.                     break;
  659.                 }
  660.                 if ( typchr != 's' && comma_list )
  661.                 free( (char *) strlist );
  662.             }
  663.             else if ( cnt >= argc )
  664.             {
  665.                 /* Fell off end looking, so must eat the arg */
  666.                 if ( typchr == 's' )
  667.                 (void)va_arg( argl, char * );
  668.                 else
  669.                 (void)va_arg( argl, ptr );
  670.             }
  671.             break;
  672.             default:         /* error */
  673.             fprintf (stderr,
  674.                  "scanargs: Corrupt or invalid format spec\n");
  675.             return 0;
  676.         }
  677.     }
  678.     }
  679.  
  680.     /*  Count up empty flags */
  681.     for (cnt=1; cnt<argc; cnt++)
  682.     if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
  683.         && !arg_used[cnt] )
  684.         check += cnt;
  685.  
  686.     /* sum from 1 to N = n*(n+1)/2 used to count up checks */
  687.     if (check != (((argc - 1) * argc) / 2))
  688.     ERROR ("extra arguments not processed");
  689.  
  690.     /* If -help, always print usage. */
  691.     if ( help )
  692.     scan_usage( argv, format );
  693.  
  694.     free(arg_used);
  695.     return 1;
  696.  
  697. error: 
  698.     if ( !no_usage )
  699.     scan_usage( argv, format );
  700.     free(arg_used);
  701.     return 0;
  702. }
  703.  
  704. void
  705. scan_usage( argv, format )
  706. char ** argv;
  707. CONST_DECL char * format;
  708. {
  709.     register CONST_DECL char * cp;
  710.  
  711.     fprintf (stderr, "usage : ");
  712.     if (*(cp = format) != ' ')
  713.     {
  714.     if ( *cp == '%' )
  715.     {
  716.         /* 
  717.          * This is bogus, but until everyone can agree on a name
  718.          * for (rindex/strrchr) ....
  719.          */
  720.         for ( cp = argv[0]; *cp != '\0'; cp++ )
  721.         ;            /* find the end of the string */
  722.         for ( ; cp > argv[0] && *cp != '/'; cp-- )
  723.         ;            /* find the last / */
  724.         if ( *cp == '/' )
  725.         cp++;
  726.         fprintf( stderr, "%s", cp );
  727.  
  728.         cp = format + 1;        /* reset to where it should be */
  729.     }
  730.     while (putc (*cp++, stderr) != ' ');
  731.     }
  732.     else
  733.     fprintf (stderr, "?? ");
  734.     while (*cp == ' ')
  735.     cp++;
  736.     (void)prformat (cp, NO);
  737. }
  738.  
  739. static CONST_DECL char *
  740. prformat (format, recurse)
  741. CONST_DECL char   *format;
  742. int     recurse;
  743. {
  744.     register CONST_DECL char  *cp;
  745.     bool    required, comma_list;
  746.     int    list_of, depth;
  747.  
  748.     cp = format;
  749.     if (recurse)
  750.     putc (' ', stderr);
  751.  
  752.     required = NO;
  753.     list_of = 0;
  754.     comma_list = NO;
  755.     while (*cp)
  756.     {
  757.     switch (*cp)
  758.     {
  759.         default:
  760.             cp++;
  761.         break;
  762.         case ' ':
  763.         case '\n':
  764.         case '\t':
  765.         /* allow annotations */
  766.         for ( ; format < cp; format++ )
  767.             putc( *format, stderr );
  768.         putc(*cp, stderr);
  769.         format = ++cp;
  770.         break;
  771.  
  772.         case '(':
  773.         /* Parentheses surround an arbitrary (parenthesis
  774.          * balanced) comment.
  775.          */
  776.         for ( ; format < cp; format++ )
  777.             putc( *format, stderr );
  778.         for ( cp++, depth = 1; *cp && depth > 0; )
  779.         {
  780.             /* Don't print last close paren. */
  781.             if ( *cp != ')' || depth > 1 )
  782.             putc( *cp, stderr );
  783.             switch( *(cp++) )
  784.             {
  785.             case '(':    depth++;        break;
  786.             case ')':    depth--;        break;
  787.             }
  788.         }
  789.         format = cp;
  790.         break;
  791.  
  792.         case '!': 
  793.         required = YES;
  794.         case '%': 
  795. reswitch:
  796.         switch (*++cp)
  797.         {
  798.             case ',':
  799.             comma_list++;
  800.             case '*':
  801.             list_of++;
  802.             goto reswitch;
  803.  
  804.             case '$':        /* "rest" of argument list */
  805.             if (!required)
  806.                 putc ('[', stderr);
  807.             for (; format < cp - 1 - list_of; format++)
  808.                 putc (*format, stderr);
  809.             fputs( " ...", stderr );
  810.             if ( !required )
  811.                 putc( ']', stderr );
  812.             break;
  813.  
  814.             case '-':         /* flags */
  815.             if (!required)
  816.                 putc ('[', stderr);
  817.             putc ('-', stderr);
  818.  
  819.             if (cp - format > 2 + list_of)
  820.                 putc ('{', stderr);
  821.             cp = format;
  822.             while (*cp != '%' && *cp != '!')
  823.                 putc (*cp++, stderr);
  824.             if (cp - format > 1 + list_of)
  825.                 putc ('}', stderr);
  826.             cp += 2;    /* skip !- or %- */
  827.             if (*cp && !isspace(*cp))
  828.                 cp = prformat (cp, YES);
  829.                     /* this is a recursive call */
  830.  
  831.             cp--;    /* don't ignore next character */
  832.  
  833.             if (!required)
  834.                 putc (']', stderr);
  835.             break;
  836.             case 's':         /* char string */
  837.             case 'd':         /* decimal # */
  838.             case 'o':         /* octal # */
  839.             case 'x':         /* hexadecimal # */
  840.             case 'f':         /* floating # */
  841.             case 'D':         /* long decimal # */
  842.             case 'O':         /* long octal # */
  843.             case 'X':         /* long hexadecimal # */
  844.             case 'F':         /* double precision floating # */
  845.             case 'n':        /* numeric arg (C format) */
  846.             case 'N':        /* long numeric arg */
  847.             if (!required)
  848.                 putc ('[', stderr);
  849.             for (; format < cp - 1 - list_of; format++)
  850.                 putc (*format, stderr);
  851.             if ( list_of != 0 )
  852.             {
  853.                 if ( comma_list )
  854.                 putc( ',', stderr );
  855.                 else
  856.                 putc( ' ', stderr );
  857.                 fputs( "...", stderr );
  858.             }
  859.             if (!required)
  860.                 putc (']', stderr);
  861.             break;
  862.             default: 
  863.             break;
  864.         }
  865.         required = NO;
  866.         list_of = NO;
  867.         comma_list = NO;
  868.         if (*cp)        /* check for end of string */
  869.             format = ++cp;
  870.         if (*cp && !isspace(*cp))
  871.             putc (' ', stderr);
  872.     }
  873.     if (recurse && isspace(*cp))
  874.         break;
  875.     }
  876.     if (!recurse)
  877.     {
  878.     for ( ; format < cp; format++ )
  879.         putc( *format, stderr );
  880.     putc ('\n', stderr);
  881.     }
  882.     return (cp);
  883. }
  884.  
  885. /* 
  886.  * isnum - determine whether a string MIGHT represent a number.
  887.  * typchr indicates the type of argument we are looking for, and
  888.  * determines the legal character set.  If comma_list is YES, then
  889.  * space and comma are also legal characters.
  890.  */
  891. static int
  892. isnum( str, typchr, comma_list )
  893. register CONST_DECL char * str;
  894. int typchr;
  895. int comma_list;
  896. {
  897.     register CONST_DECL char *allowed, *digits, *cp;
  898.     int hasdigit = NO;
  899.  
  900.     switch( typchr )
  901.     {
  902.     case 'n':
  903.     case 'N':
  904.         allowed = " \t,+-x0123456789abcdefABCDEF";
  905.         break;
  906.     case 'd':
  907.     case 'D':
  908.         allowed = " \t,+-0123456789";
  909.         break;
  910.     case 'o':
  911.     case 'O':
  912.         allowed = " \t,01234567";
  913.         break;
  914.     case 'x':
  915.     case 'X':
  916.         allowed = " \t,0123456789abcdefABCDEF";
  917.         break;
  918.     case 'f':
  919.     case 'F':
  920.         allowed = " \t,+-eE.0123456789";
  921.         break;
  922.     case 's':            /* only throw out decimal numbers */
  923.     default:
  924.         allowed = " \t,+-.0123456789";
  925.         break;
  926.     }
  927.     digits = allowed;
  928.     while ( *digits != '0' )
  929.     digits++;
  930.     if ( ! comma_list )
  931.     allowed += 3;              /* then don't allow space, tab, comma */
  932.  
  933.     while ( *str != '\0' )
  934.     {
  935.         for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
  936.             ;
  937.         if ( *cp == '\0' )
  938.         return NO;             /* if not in allowed chars, not number */
  939.     if ( cp - digits >= 0 )
  940.         hasdigit = YES;
  941.     str++;
  942.     }
  943.     return hasdigit;
  944. }
  945.